/** Double-include prevention */
#if defined _tfx_included_
  #endinput
#endif
#define _tfx_included_


stock EmitSoundClient(const String:sound[], client) {
	decl Float:pos[3];	
	GetClientAbsOrigin(client, pos);

	EmitAmbientSound(sound, pos, client);
}

// Particles ------------------------------------------------------------------
// Particle Attachment Types  -------------------------------------------------

/* CreateParticle()
**
** Creates a particle at an entity's position. Attach determines the attachment
** type (0 = not attached, 1 = normal attachment, 2 = head attachment). Allows
** offsets from the entity's position. Returns the handle of the timer that
** deletes the particle (should you wish to trigger it early).
** ------------------------------------------------------------------------- */
#define NO_ATTACH		0
#define ATTACH_NORMAL		1
#define ATTACH_HEAD		2

stock Handle:CreateParticle(String:type[], Float:time, entity, attach=NO_ATTACH, Float:xOffs=0.0, Float:yOffs=0.0, Float:zOffs=0.0)
{
	new particle = CreateEntityByName("info_particle_system");
	
	// Check if it was created correctly
	if (IsValidEdict(particle)) {
		decl Float:pos[3];

		// Get position of entity
		GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
		
		// Add position offsets
		pos[0] += xOffs;
		pos[1] += yOffs;
		pos[2] += zOffs;
		
		// Teleport, set up
		TeleportEntity(particle, pos, NULL_VECTOR, NULL_VECTOR);
		DispatchKeyValue(particle, "effect_name", type);

		if (attach != NO_ATTACH) {
			SetVariantString("!activator");
			AcceptEntityInput(particle, "SetParent", entity, particle, 0);
		
			if (attach == ATTACH_HEAD) {
				SetVariantString("head");
				AcceptEntityInput(particle, "SetParentAttachmentMaintainOffset", particle, particle, 0);
			}
		}
		
		// All entities in presents are given a targetname to make clean up easier
		DispatchKeyValue(particle, "targetname", "present");

		// Spawn and start
		DispatchSpawn(particle);
		ActivateEntity(particle);
		AcceptEntityInput(particle, "Start");
		
		return CreateTimer(time, DeleteParticle, particle);
	} else {
		LogError("Presents (CreateParticle): Could not create info_particle_system");
	}
	
	return INVALID_HANDLE;
}

/* DeleteParticle()
**
** Deletes a particle.
** ------------------------------------------------------------------------- */
public Action:DeleteParticle(Handle:timer, any:particle)
{
	if (IsValidEdict(particle)) {
		new String:classname[64];
		GetEdictClassname(particle, classname, sizeof(classname));
		
		if (StrEqual(classname, "info_particle_system", false)) {
			RemoveEdict(particle);
		}
	}
}

new g_clientOverlay[MAXPLAYERS+1];
new Handle:overlayTimer = INVALID_HANDLE;

/* ShowOverlay()
**
** Shows an overlay.
** ------------------------------------------------------------------------- */
public ShowOverlay(client, String:overlay[], Float:time)
{	
	new Handle:pack;
	
	g_clientOverlay[client] = true;
	
	OverlayCommand(client, overlay);
	
	CreateDataTimer(0.1, Timer_MaintainOverlay, pack, TIMER_REPEAT);
	
	WritePackCell(pack, client);
	WritePackString(pack, overlay);
	WritePackFloat(pack, time);
}

/* OverlayCommand()
**
** Runs r_screenoverlay on a client (removing cheat flags and then adding them again quickly).
** ------------------------------------------------------------------------- */
public OverlayCommand(client, String:overlay[])
{	
	if (client && IsClientInGame(client) && !IsClientInKickQueue(client)) {
		new flags; 
		
		flags  = GetCommandFlags("r_screenoverlay") & (~FCVAR_CHEAT);
		SetCommandFlags("r_screenoverlay", flags);

		ClientCommand(client, "r_screenoverlay %s", overlay);
		
		if (overlayTimer != INVALID_HANDLE) {
			KillTimer(overlayTimer);
		}
		
		overlayTimer = CreateTimer(0.1, Timer_OverlayBlockCommand);
	}
}

/* Timer_MaintainOverlay()
**
** Maintains an overlay on a client for a given time. Otherwise it gets reset by fire, etc.
** ------------------------------------------------------------------------- */
public Action:Timer_MaintainOverlay(Handle:timer, Handle:pack)
{
	new client, String:overlay[64], Float:time;
	
	ResetPack(pack);
	client = ReadPackCell(pack);
	ReadPackString(pack, overlay, 64);
	time = ReadPackFloat(pack);
	
	if (client && IsClientInGame(client) && !IsClientInKickQueue(client)) {
		time -= 0.1;
		
		if ((RoundToFloor(time * 10) <= 0) || !g_clientOverlay[client]) {
			OverlayCommand(client, "\"\"");
			g_clientOverlay[client] = false;
			
			return Plugin_Stop;
		}
		
		OverlayCommand(client, overlay);
		
		ResetPack(pack);
		WritePackCell(pack, client);
		WritePackString(pack, overlay);
		WritePackFloat(pack, time);
		
		return Plugin_Continue;
	} else {
		return Plugin_Stop;
	}
}

/* Timer_OverlayBlockCommand()
**
** Blocks r_screenoverlay command.
** ------------------------------------------------------------------------- */
public Action:Timer_OverlayBlockCommand(Handle:timer)
{
	overlayTimer = INVALID_HANDLE;
	
	new flags = GetCommandFlags("r_screenoverlay") | (FCVAR_CHEAT);
	SetCommandFlags("r_screenoverlay", flags);
}


#define DMG_GENERIC			0
#define DMG_CRUSH			(1 << 0)
#define DMG_BULLET			(1 << 1)
#define DMG_SLASH			(1 << 2)
#define DMG_BURN			(1 << 3)
#define DMG_VEHICLE			(1 << 4)
#define DMG_FALL			(1 << 5)
#define DMG_BLAST			(1 << 6)
#define DMG_CLUB			(1 << 7)
#define DMG_SHOCK			(1 << 8)
#define DMG_SONIC			(1 << 9)
#define DMG_ENERGYBEAM			(1 << 10)
#define DMG_PREVENT_PHYSICS_FORCE	(1 << 11)
#define DMG_NEVERGIB			(1 << 12)
#define DMG_ALWAYSGIB			(1 << 13)
#define DMG_DROWN			(1 << 14)
#define DMG_TIMEBASED			(DMG_PARALYZE | DMG_NERVEGAS | DMG_POISON | DMG_RADIATION | DMG_DROWNRECOVER | DMG_ACID | DMG_SLOWBURN)
#define DMG_PARALYZE			(1 << 15)
#define DMG_NERVEGAS			(1 << 16)
#define DMG_POISON			(1 << 17)
#define DMG_RADIATION			(1 << 18)
#define DMG_DROWNRECOVER		(1 << 19)
#define DMG_ACID			(1 << 20)
#define DMG_SLOWBURN			(1 << 21)
#define DMG_REMOVENORAGDOLL		(1 << 22)
#define DMG_PHYSGUN			(1 << 23)
#define DMG_PLASMA			(1 << 24)
#define DMG_AIRBOAT			(1 << 25)
#define DMG_DISSOLVE			(1 << 26)
#define DMG_BLAST_SURFACE		(1 << 27)
#define DMG_DIRECT			(1 << 28)
#define DMG_BUCKSHOT			(1 << 29)

stock DealDamage(Float:pos[3],damage,attacker=0,dmg_type=DMG_GENERIC)
{
	if(damage>0)
	{
		new String:dmg_str[16];
		IntToString(damage,dmg_str,16);
		new String:dmg_type_str[32];
		IntToString(dmg_type,dmg_type_str,32);
		new pointHurt=CreateEntityByName("point_hurt");
		
		if(pointHurt)
		{
			//DispatchKeyValue(pointHurt,"DamageTarget","war3_hurtme");
			DispatchKeyValue(pointHurt, "DamageRadius", "480.0");
			DispatchKeyValue(pointHurt,"Damage",dmg_str);
			DispatchKeyValue(pointHurt,"DamageType",dmg_type_str);
			DispatchKeyValue(pointHurt,"classname","point_hurt");
			DispatchSpawn(pointHurt);

			TeleportEntity(pointHurt, pos, NULL_VECTOR, NULL_VECTOR);						
			AcceptEntityInput(pointHurt,"Hurt",-1,(attacker>0)?attacker:-1);
			

			RemoveEdict(pointHurt);
		}
	}
}


public AddCond(client, cond) {
	new Handle:cvar = FindConVar("sv_cheats"), bool:enabled = GetConVarBool(cvar), flags = GetConVarFlags(cvar);
	if(!enabled) {
		SetConVarFlags(cvar, flags^(FCVAR_NOTIFY|FCVAR_REPLICATED));
		SetConVarBool(cvar, true);
	}
	FakeClientCommand(client, "addcond %i", cond);
	if(!enabled) {
		SetConVarBool(cvar, false);
		SetConVarFlags(cvar, flags);
	}
}

public RemoveCond(client, cond) {
	new Handle:cvar = FindConVar("sv_cheats"), bool:enabled = GetConVarBool(cvar), flags = GetConVarFlags(cvar);
	if(!enabled) {
		SetConVarFlags(cvar, flags^(FCVAR_NOTIFY|FCVAR_REPLICATED));
		SetConVarBool(cvar, true);
	}
	FakeClientCommand(client, "removecond %i", cond);
	if(!enabled) {
		SetConVarBool(cvar, false);
		SetConVarFlags(cvar, flags);
	}
}

#define BLACK      {0,0,0,255}
#define RED        {255,0,0,255}
#define INVISIBLE  {255,255,255,10}
#define NORMAL     {255,255,255,255}


/* ColorizePlayer()
**
** Colorizes a client.
**
** Credit to linux_lower.
** ------------------------------------------------------------------------- */
public ColorizePlayer(client, color[4])
{
	new maxents = GetMaxEntities();
	// Colorize player and weapons
	new m_hMyWeapons = FindSendPropOffs("CBasePlayer", "m_hMyWeapons");	
	new g_ownerOffset = FindSendPropInfo("CTFWearableItem", "m_hOwnerEntity");
	
	for(new i = 0, weapon; i < 47; i += 4)
	{
		weapon = GetEntDataEnt2(client, m_hMyWeapons + i);
	
		if(weapon > -1 )
		{
			SetEntityRenderMode(weapon, RENDER_TRANSCOLOR);
			SetEntityRenderColor(weapon, color[0], color[1],color[2], color[3]);
		}
	}
	
	SetEntityRenderMode(client, RENDER_TRANSCOLOR);	
	SetEntityRenderColor(client, color[0], color[1], color[2], color[3]);
	
	// Colorize any wearable items
	for (new i = MaxClients + 1; i <= maxents; i++) {
		if (!IsValidEntity(i)) continue;
		
		decl String:netclass[32];
		GetEntityNetClass(i, netclass, sizeof(netclass));
		
		if (strcmp(netclass, "CTFWearableItem") == 0) {
			if (GetEntDataEnt2(i, g_ownerOffset) == client) {
				SetEntityRenderMode(i, RENDER_TRANSCOLOR);
				SetEntityRenderColor(i, color[0], color[1], color[2], color[3]);
			}
		}
	}
}